package com.ruoyi.generator.controller

import com.alibaba.druid.DbType
import com.alibaba.druid.sql.SQLUtils
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement
import com.ruoyi.common.annotation.Log
import com.ruoyi.common.core.controller.BaseController
import com.ruoyi.common.core.domain.AjaxResult
import com.ruoyi.common.core.page.TableDataInfo
import com.ruoyi.common.core.text.Convert.toStrArray
import com.ruoyi.common.enums.BusinessType
import com.ruoyi.common.utils.SecurityUtils
import com.ruoyi.common.utils.sql.SqlUtil
import com.ruoyi.generator.domain.GenTable
import com.ruoyi.generator.service.IGenTableColumnService
import com.ruoyi.generator.service.IGenTableService
import org.apache.commons.io.IOUtils
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.security.access.prepost.PreAuthorize
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.*
import java.io.IOException
import javax.servlet.http.HttpServletResponse

/**
 * 代码生成 操作处理
 *
 * @author ruoyi
 */
@RestController
@RequestMapping("/tool/gen")
open class GenController : BaseController() {
    @Autowired
    private lateinit var  genTableService: IGenTableService

    @Autowired
    private lateinit var  genTableColumnService: IGenTableColumnService

    /**
     * 查询代码生成列表
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
    @GetMapping("/list")
    open fun genList(genTable: GenTable?): TableDataInfo {
        startPage()
        val list = genTableService.selectGenTableList(genTable)
        return getDataTable(list)
    }

    /**
     * 修改代码生成业务
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:query')")
    @GetMapping(value = ["/{tableId}"])
    open fun getInfo(@PathVariable tableId: Long): AjaxResult {
        val table = genTableService.selectGenTableById(tableId)
        val tables = genTableService.selectGenTableAll()
        val list = genTableColumnService.selectGenTableColumnListByTableId(tableId)
        val map: MutableMap<String, Any> = mutableMapOf()
        map["info"] = table!!
        map["rows"] = list
        map["tables"] = tables
        return success(map)
    }

    /**
     * 查询数据库列表
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
    @GetMapping("/db/list")
    open fun dataList(genTable: GenTable?): TableDataInfo {
        startPage()
        val list = genTableService.selectDbTableList(genTable)
        return getDataTable(list)
    }

    /**
     * 查询数据表字段列表
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
    @GetMapping(value = ["/column/{tableId}"])
    open fun columnList(@PathVariable tableId: Long): TableDataInfo {
        val dataInfo = TableDataInfo()
        val list = genTableColumnService.selectGenTableColumnListByTableId(tableId)
        dataInfo.rows = list
        dataInfo.total = list.size.toLong()
        return dataInfo
    }

    /**
     * 导入表结构（保存）
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:import')")
    @Log(title = "代码生成", businessType = BusinessType.IMPORT)
    @PostMapping("/importTable")
    open fun importTableSave(tables: String): AjaxResult {
        val tableNames :Array<String> = toStrArray(tables)
        // 查询表信息
        val tableList : List<GenTable> = genTableService.selectDbTableListByNames(tableNames)
        genTableService.importGenTable(tableList, SecurityUtils.username)
        return success()
    }

    /**
     * 创建表结构（保存）
     */
    @PreAuthorize("@ss.hasRole('admin')")
    @Log(title = "创建表", businessType = BusinessType.OTHER)
    @PostMapping("/createTable")
    open fun createTableSave(sql: String?): AjaxResult {
        return try {
            SqlUtil.filterKeyword(sql)
            val sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql)
            val tableNames: MutableList<String> = mutableListOf()
            for (sqlStatement in sqlStatements) {
                if (sqlStatement is MySqlCreateTableStatement) {
                    if (genTableService.createTable(sqlStatement.toString())) {
                        val tableName = sqlStatement.tableName.replace("`".toRegex(), "")
                        tableNames.add(tableName)
                    }
                }
            }
            val tableList = genTableService.selectDbTableListByNames(tableNames.toTypedArray())
            val operName = SecurityUtils.username
            genTableService.importGenTable(tableList, operName)
            AjaxResult.success()
        } catch (e: Exception) {
            logger.error(e.message, e)
            AjaxResult.error("创建表结构异常")
        }
    }

    /**
     * 修改保存代码生成业务
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
    @Log(title = "代码生成", businessType = BusinessType.UPDATE)
    @PutMapping
    open fun editSave(@Validated @RequestBody genTable: GenTable): AjaxResult {
        genTableService.validateEdit(genTable)
        genTableService.updateGenTable(genTable)
        return success()
    }

    /**
     * 删除代码生成
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:remove')")
    @Log(title = "代码生成", businessType = BusinessType.DELETE)
    @DeleteMapping("/{tableIds}")
    open fun remove(@PathVariable tableIds: Array<Long?>?): AjaxResult {
        genTableService.deleteGenTableByIds(tableIds)
        return success()
    }

    /**
     * 预览代码
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:preview')")
    @GetMapping("/preview/{tableId}")
    @Throws(IOException::class)
    open fun preview(@PathVariable("tableId") tableId: Long?): AjaxResult {
        val dataMap = genTableService.previewCode(tableId)
        return success(dataMap)
    }

    /**
     * 生成代码（下载方式）
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
    @GetMapping("/download/{tableName}")
    @Throws(IOException::class)
    open fun download(response: HttpServletResponse, @PathVariable("tableName") tableName: String) {
        val data = genTableService.downloadCode(tableName)
        genCode(response, data)
    }

    /**
     * 生成代码（自定义路径）
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
    @GetMapping("/genCode/{tableName}")
    open fun genCode(@PathVariable("tableName") tableName: String?): AjaxResult {
        genTableService.generatorCode(tableName)
        return success()
    }

    /**
     * 同步数据库
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
    @Log(title = "代码生成", businessType = BusinessType.UPDATE)
    @GetMapping("/synchDb/{tableName}")
    open fun synchDb(@PathVariable("tableName") tableName: String?): AjaxResult {
        genTableService.synchDb(tableName)
        return success()
    }

    /**
     * 批量生成代码
     */
    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
    @GetMapping("/batchGenCode")
    @Throws(IOException::class)
    open fun batchGenCode(response: HttpServletResponse, tables: String?) {
        val tableNames = toStrArray(tables!!)
        val data = genTableService.downloadCode(tableNames)
        genCode(response, data)
    }

    /**
     * 生成zip文件
     */
    @Throws(IOException::class)
    private fun genCode(response: HttpServletResponse, data: ByteArray) {
        response.reset()
        response.addHeader("Access-Control-Allow-Origin", "*")
        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition")
        response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"")
        response.addHeader("Content-Length", "" + data.size)
        response.contentType = "application/octet-stream; charset=UTF-8"
        IOUtils.write(data, response.outputStream)
    }
}
